package com.example.user.app;

import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;

import com.google.inject.Inject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import roboguice.content.RoboContentProvider;
import roboguice.inject.ContentView;

/**
 * Created by hzn on 14-6-26.
 */
public class ContactsProvider extends RoboContentProvider {
    @Inject
    private Context mContext;
    @Inject
    private ContentResolver mContentResolver;

    public static final String AUTHORITY = "com.example.user.app.contacts";

    private static final int DATABASE_VERSION = 1;

    private static final String TABLE_CONTACTS = "contacts";
    private Map<String, DatabaseHelper> mDatabaseHelpers;

    private static final int CONTACTS = 1;
    private static final int CONTACT_ID = 2;

    private static final int POSITION_DBNAME = 0;

    private static final UriMatcher sUriMatcher;
    private static final Map<String, String> sContactsProjectionMap;

    static {
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(AUTHORITY, "*/" + TABLE_CONTACTS, CONTACTS);
        sUriMatcher.addURI(AUTHORITY, "*/" + TABLE_CONTACTS + "/#", CONTACT_ID);

        sContactsProjectionMap = new HashMap<String, String>();
        sContactsProjectionMap.put(Contacts._ID, Contacts._ID);
        sContactsProjectionMap.put(Contacts.NAME, Contacts.NAME);
        sContactsProjectionMap.put(Contacts.MOBILE_NUMBER, Contacts.MOBILE_NUMBER);
        sContactsProjectionMap.put(Contacts.CREATE_AT, Contacts.CREATE_AT);
    }

    private String getDBNameFromUri(Uri uri) {
        try {
            return uri.getPathSegments().get(POSITION_DBNAME);
        } catch (NullPointerException e) {
            e.printStackTrace();
            return "default";
        }
    }

    private DatabaseHelper getDatabaseHelperFromUri(Uri uri) {
        String dbName = getDBNameFromUri(uri);

        if (mDatabaseHelpers.containsKey(dbName)) {
            return mDatabaseHelpers.get(dbName);
        } else {
            DatabaseHelper helper = new DatabaseHelper(mContext, dbName);
            mDatabaseHelpers.put(dbName, helper);

            return helper;
        }
    }

    @Override
    public boolean onCreate() {
        mDatabaseHelpers = new HashMap<String, DatabaseHelper>();
        return super.onCreate();
    }

    private static class DatabaseHelper extends SQLiteOpenHelper {

        private static final String _SCHEMA_CONTACTS = "(" +
                "_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
                "name TEXT NOT NULL, " +
                "mobile_number TEXT NOT NULL, " +
                "create_at INTEGER" +
                ")";

        private static final String SCHEMA_CONTACTS =
                "CREATE TABLE " + TABLE_CONTACTS + " " + _SCHEMA_CONTACTS;


        public DatabaseHelper(Context context, String dbName) {
            super(context, dbName, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL(SCHEMA_CONTACTS);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            throw new SQLException("Upgrade is unsupported.");
        }
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

        switch (sUriMatcher.match(uri)) {
            case CONTACTS:
                qb.setTables(TABLE_CONTACTS);
                qb.setProjectionMap(sContactsProjectionMap);
                break;

            default:
                throw new IllegalArgumentException("Unknown URI");
        }

        DatabaseHelper databaseHelper = getDatabaseHelperFromUri(uri);
        if (databaseHelper == null) {
            throw new UnsupportedOperationException("Unknown URI");
        }

        SQLiteDatabase db = databaseHelper.getReadableDatabase();
        Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, null);

        return c;
    }

    @Override
    public String getType(Uri uri) {
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues initialValues) {
        int match = sUriMatcher.match(uri);
        if (match != CONTACTS) {
            throw new IllegalArgumentException("Unknow URI " + uri);
        }

        ContentValues values = new ContentValues(initialValues);

        DatabaseHelper helper = getDatabaseHelperFromUri(uri);
        if (helper == null) {
            throw new UnsupportedOperationException("Unknow URI " + uri);
        }

        SQLiteDatabase db = helper.getWritableDatabase();
        boolean success = false;
        List<Uri> notifications = new ArrayList<Uri>();

        try {
            beginTransaction(db);

            long rowId;
            rowId = db.insertOrThrow(TABLE_CONTACTS, null, values);


            if (rowId > 0) {
                notifications.add(uri);

                Uri contactUri = ContentUris.withAppendedId(uri, rowId);
                notifications.add(contactUri);

                success = setTransactionSuccessful(db);

                return contactUri;
            }

            throw new SQLException("Failed to insert row into " + uri);
        } finally {
            endTransaction(db, success);
            for (Uri one : notifications) {
                mContentResolver.notifyChange(one, null);
            }
        }

    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        return 0;
    }

    @TargetApi(11)
    private void beginTransaction(SQLiteDatabase db) {
        if (android.os.Build.VERSION.SDK_INT >= 11)
            db.beginTransactionNonExclusive();
        else
            // this is because API < 11 doesn't have beginTransactionNonExclusive()
            db.execSQL("BEGIN IMMEDIATE");
    }

    private boolean setTransactionSuccessful(SQLiteDatabase db) {
        if (android.os.Build.VERSION.SDK_INT >= 11)
            db.setTransactionSuccessful();
        return true;
    }

    private void endTransaction(SQLiteDatabase db, boolean success) {
        if (android.os.Build.VERSION.SDK_INT >= 11)
            db.endTransaction();
        else
            db.execSQL(success ? "COMMIT" : "ROLLBACK");
    }
}
